/**
 * Theory of operation:
 *
 * - two buttons on android app: open door - close door - information to arduino is sent via BT
 *
 *
 * - VAR doorStateIndicator contains an information whether the door is closed (0), open (2),
 *   or somewhere in between (1)
 *
 * REQUIRED COMPONENTS:
 *  - 2 limit switches
 *
 * REQUIRED MODULES:
 * - bluetooth module HC-05
 * - motor driver module L298N Dual H-Bridge Stepper Motor Driver Controller Module Board
 * - current sensor 20A ACS712
 *
 */

#include "GarageDoor.h"


//pins
const int ledPin = 13;					//When the is an activity the led blinks
const int motorDirIn1Pin = 2; 			//H-bridge IN1 pin
const int motorDirIn2Pin = 4; 			//H-bridge IN2 pin
const int motorEnaPin = 3; 				//PWM motor pin
const int upperLimitSwitchPin = 7; 		//Upper switch pin that stops the door
const int lowerLimitSwitchPin = 8; 		//Lower switch pin that stops the door
const int manualOpenPin = 9;			//Besides the bluetooth control the door can be operated with manual switch  -open button
const int manualClosePin = 10;			//Besides the bluetooth control the door can be operated with manual switch - close button
const int psRelayPin1 = 5;				//the relay that starts power supply #1
const int psRelayPin2 = 6;				//the relay that starts power supply #2
const int currentSensorPin = A0;		//analog input pin for current sensor

//constants
const int DOOR_CLOSED = 0;
const int DOOR_OPEN = 2;
const int DOOR_IN_BETWEEN = 1;
const int POWER_SUPPLY_ON = 1;
const int POWER_SUPPLY_OFF = 0;

//vars that can be accessed via BT
int motorSpeed = 200;							//motor speed 0..255
int blinkInterval = 500;						//LED indicator blink interval
int inactiveInterval = 60000;					//when this interval is reached the power supplies go off
int waitForPsInterval = 500;					//how many miliseconds to wait before the Power supply wakes up
int maxOpeningCurrent = 512;					//if the current is larger than this than the door stops
int maxClosingCurrent = 512;					//if the current is larger than this than the door stops

//runtime vars
int doorStateIndicator = DOOR_CLOSED; 			//Indicates if the door is open or not - closed 0, open 2, in between 1
int lowerLimitSwitchState;						//pulldown resistor needs to be applied
int upperLimitSwitchState;						//pulldown resistor needs to be applied
int manualOpenState;							//pulldown resistor needs to be applied
int manualCloseState;							//pulldown resistor needs to be applied
int powSupplyRelaysState = POWER_SUPPLY_OFF; 	//initial state is off, arduino will be powered with 5V phone charger, and the power supply will kick in when needed
int current = 0;								//initial state of the current sensor

int ledState = LOW;             				// ledState used to set the LED
long previousMillis = 0;        				// will store last time LED was updated
int stopped = 0;

void stopDoor()
{
	digitalWrite(motorDirIn1Pin,LOW);
	digitalWrite(motorDirIn2Pin,LOW);
	stopped = 1;
	//Serial.println("Vrata zaustavljena.");
}

//closes the door
void closeDoor()
{
	if(powSupplyRelaysState == POWER_SUPPLY_OFF){
		startPSs();
		delay(waitForPsInterval);
	}
	lowerLimitSwitchState = digitalRead(lowerLimitSwitchPin);
	if(lowerLimitSwitchState == LOW){
		digitalWrite(motorDirIn1Pin,HIGH);
		digitalWrite(motorDirIn2Pin,LOW);
		analogWrite(motorEnaPin,motorSpeed);
		doorStateIndicator = DOOR_IN_BETWEEN;
		stopped = 0;
	}

	do{
		delay(10);
		lowerLimitSwitchState = digitalRead(lowerLimitSwitchPin);
		current = analogRead(A0);
		if(current > maxClosingCurrent){stopDoor();}
		if(Serial.available()){
			char ch = Serial.read();
			if(ch == '2'){
				stopDoor();
				break;
			}
		}
		blinkLed();
	}while(lowerLimitSwitchState == LOW);

	if(stopped == 0){
		stopDoor();
		digitalWrite(ledPin, LOW);
		doorStateIndicator = DOOR_CLOSED;
		//Serial.println("Vrata zatvorena.");
	}
}

//opens the door
void openDoor()
{
	if(powSupplyRelaysState == POWER_SUPPLY_OFF){
		startPSs();
		delay(waitForPsInterval);
	}
	upperLimitSwitchState = digitalRead(upperLimitSwitchPin);
	if(upperLimitSwitchState == LOW){
		digitalWrite(motorDirIn1Pin,LOW);
		digitalWrite(motorDirIn2Pin,HIGH);
		analogWrite(motorEnaPin,motorSpeed);
		doorStateIndicator = DOOR_IN_BETWEEN;
		stopped = 0;
	}

	do{
		delay(10);
		upperLimitSwitchState = digitalRead(upperLimitSwitchPin);
		current = analogRead(A0);
		if(current > maxOpeningCurrent){stopDoor();}
		if(Serial.available()){
			char ch = Serial.read();
			if(ch == '2'){
				stopDoor();
				break;
			}
		}
		blinkLed();
	}while(upperLimitSwitchState == LOW);

	if(stopped == 0){
		stopDoor();
		digitalWrite(ledPin, LOW);
		doorStateIndicator = DOOR_OPEN;
		//Serial.println("Vrata otvorena.");
	}
}

//starts the power supplies
void startPSs()
{
	digitalWrite(psRelayPin1,HIGH);
	digitalWrite(psRelayPin2,HIGH);
	powSupplyRelaysState = POWER_SUPPLY_ON;
}

void stopPSs()
{
	digitalWrite(psRelayPin1,LOW);
	digitalWrite(psRelayPin2,LOW);
	powSupplyRelaysState = POWER_SUPPLY_OFF;
}

//blinks the led
void blinkLed()
{
	unsigned long currentMillis = millis();

	if(currentMillis - previousMillis > blinkInterval) {
	    // save the last time you blinked the LED
		previousMillis = currentMillis;
	    // if the LED is off turn it on and vice-versa:
		if (ledState == LOW)
	      ledState = HIGH;
	    else
	      ledState = LOW;
	    // set the LED with the ledState of the variable:
	    digitalWrite(ledPin, ledState);
	}
}

//The setup function is called once at startup of the sketch
void setup()
{
	pinMode(lowerLimitSwitchPin, INPUT);
	pinMode(upperLimitSwitchPin, INPUT);
	pinMode(ledPin, OUTPUT);
	pinMode(motorDirIn1Pin, OUTPUT);
	pinMode(motorDirIn2Pin, OUTPUT);
	pinMode(manualOpenPin, OUTPUT);
	pinMode(manualClosePin, OUTPUT);
	pinMode(psRelayPin1, OUTPUT);
	pinMode(psRelayPin2, OUTPUT);
	//begin the serial communication
	Serial.begin(9600);
}

// The loop function is called in an endless loop
void loop()
{
	if(Serial.available()){
		char ch = Serial.read();
		if(ch == '0'){
			//check if door is open, or in between
			if(doorStateIndicator > DOOR_CLOSED){
				closeDoor();
			}
		}else if(ch == '1'){
			//check if door is open, or in between
			if(doorStateIndicator < DOOR_OPEN){
				openDoor();
			}
		}
	}

	manualOpenState = digitalRead(manualOpenPin);
	if(manualOpenState == HIGH){
		openDoor();
	}

	manualCloseState = digitalRead(manualClosePin);
	if(manualCloseState == HIGH){
		closeDoor();
	}
}
